import { useState } from "react"
import { Box, HStack, IconButton, Select, Badge } from "@chakra-ui/react"
import Editor from "@monaco-editor/react"
import { saveAs } from "file-saver"
import { BsFileCode } from "icons/bs/BsFileCode"
import YAML from "yaml"
import JsYaml from "js-yaml"
import { FiDownload } from "icons/fi/FiDownload"
import { ApiEndpointDetailed } from "@common/types"
import { SpecExtension } from "@common/enums"
import { DataHeading } from "components/utils/Card"
import EmptyView from "components/utils/EmptyView"
import { EXTENSION_TO_TYPE } from "~/constants"

interface SpecComponentProps {
  endpoint: ApiEndpointDetailed
}

const SpecComponent: React.FC<SpecComponentProps> = ({ endpoint }) => {
  const [specString, setSpecString] = useState<string>(
    endpoint.openapiSpec?.spec,
  )
  const [currExtension, setCurrExtension] = useState<SpecExtension>(
    endpoint.openapiSpec?.extension,
  )

  const blob = new Blob([specString], {
    type: EXTENSION_TO_TYPE[currExtension],
  })

  const changeExtensionHandler = (e: React.ChangeEvent<HTMLSelectElement>) => {
    const extension = e.target.value
    if (extension === endpoint.openapiSpec.extension) {
      setSpecString(endpoint.openapiSpec.spec)
      setCurrExtension(endpoint.openapiSpec.extension)
    } else if (extension === SpecExtension.YAML) {
      const obj = JSON.parse(specString)
      setSpecString(YAML.stringify(obj))
      setCurrExtension(SpecExtension.YAML)
    } else if (extension === SpecExtension.JSON) {
      const specObj = JsYaml.load(specString)
      const jsonString = JSON.stringify(specObj, null, 2)
      setSpecString(jsonString)
      setCurrExtension(SpecExtension.JSON)
    }
  }

  const downloadFileHandler = () => {
    saveAs(blob, `${endpoint?.openapiSpec?.name}.${currExtension}`)
  }

  return (
    <Box w={{ base: "full", lg: "50%" }} h="full">
      {endpoint?.openapiSpec ? (
        <Box h="full" w="full">
          <HStack
            w="full"
            px="4"
            borderWidth={1}
            py="2"
            justifyContent="space-between"
          >
            <HStack w="full">
              <HStack wordBreak="break-all">
                <BsFileCode fontSize="30px" />
                <DataHeading fontSize="lg">
                  {endpoint?.openapiSpec?.name}
                </DataHeading>
              </HStack>
              <Box>
                {endpoint?.openapiSpec?.isAutoGenerated && (
                  <Badge px={1} py={0.5} rounded="full" colorScheme="blue">
                    Generated
                  </Badge>
                )}
              </Box>
            </HStack>
            <HStack spacing="4">
              <Select
                defaultValue={endpoint?.openapiSpec?.extension}
                w="max-content"
                onChange={changeExtensionHandler}
              >
                <option value={SpecExtension.YAML}>yaml</option>
                <option value={SpecExtension.JSON}>json</option>
              </Select>
              <IconButton
                onClick={downloadFileHandler}
                borderWidth={1}
                aria-label="download-button"
                icon={<FiDownload />}
              />
            </HStack>
          </HStack>
          <Box
            overflow="hidden"
            h={{
              base: "700px",
              lg: "calc(100% - 105px)",
              xl: "calc(100% - 80px)",
            }}
          >
            <Editor
              width="100%"
              defaultLanguage="yaml"
              value={specString || "No spec generated yet."}
              options={{
                minimap: {
                  enabled: false,
                },
                automaticLayout: true,
                readOnly: true,
                renderIndentGuides: false,
                scrollBeyondLastLine: false,
              }}
            />
          </Box>
        </Box>
      ) : (
        <EmptyView
          visibility={{ base: "hidden", lg: "visible" }}
          h="full"
          text="No OpenAPI Spec generated yet."
        />
      )}
    </Box>
  )
}

export default SpecComponent
